package com.nidu.demo.tenant.executor.command;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.nidu.demo.common.enums.RoleCodeEnum;
import com.nidu.demo.common.enums.StatusEnum;
import com.nidu.demo.role.gateway.RoleGateway;
import com.nidu.demo.role.gateway.RoleMenuGateway;
import com.nidu.demo.role.model.Role;
import com.nidu.demo.role.model.RoleCriteria;
import com.nidu.demo.tenant.ability.TenantDomainService;
import com.nidu.demo.tenant.ability.TenantPackageDomainService;
import com.nidu.demo.tenant.convertor.TenantConvertor;
import com.nidu.demo.tenant.dto.TenantCO;
import com.nidu.demo.tenant.dto.TenantUpdateCmd;
import com.nidu.demo.tenant.gateway.TenantGateway;
import com.nidu.demo.tenant.model.Tenant;
import com.nidu.demo.tenant.model.TenantPackage;
import com.nidu.demo.tenant.util.TenantUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Set;
import java.util.Objects;
import java.util.List;

/**
 * 租户更新命令执行器
 *
 * @author auto
 */
@Component
@RequiredArgsConstructor
public class TenantUpdateCmdExe {

    private final TenantConvertor convertor;

    private final TenantDomainService domainService;

    private final TenantPackageDomainService packageDomainService;

    private final TenantGateway gateway;

    private final RoleGateway roleGateway;

    private final RoleMenuGateway roleMenuGateway;

    public SingleResponse<TenantCO> execute(TenantUpdateCmd cmd) {
        // 1. 转换为领域对象
        Tenant tenant = Tenant.update(cmd.getId(), cmd.getName(), cmd.getAdminId(), cmd.getWebsite(), cmd.getPackageId(),
                cmd.getExpireTime(), cmd.getAccountCount(),
                cmd.getRemark(), cmd.getSortOrder());
        // 2. 检查租户名称是否重复
        domainService.validateDuplicate(tenant.getName(), tenant.getId());

        // 3. 检查套餐是否被禁用
        TenantPackage tenantPackage = packageDomainService.validateTenantPackage(cmd.getPackageId());

        // 4. 调用网关保存
        Tenant save = this.updateTenant(tenant, tenantPackage);

        // 5. 转换为DTO返回
        TenantCO tenantCO = convertor.toClientObject(save);

        return SingleResponse.of(tenantCO);
    }

    public Response updateStatus(Long id, StatusEnum status) {
        gateway.updateStatus(id, status.getValue());
        return Response.buildSuccess();
    }

    @Transactional
    private Tenant updateTenant(Tenant tenant, TenantPackage tenantPackage) {
        Tenant save = gateway.update(tenant);

        // 如果套餐发生变化，则修改其角色的权限
        if (!Objects.equals(save.getPackageId(), tenantPackage.getId())) {
            TenantUtils.execute(save.getId(), () -> {
                // 获取该租户的所有角色
                List<Role> roles = roleGateway.listByCondition(new RoleCriteria());
                roles.forEach(role -> {
                    // 如果是租户管理员，重新分配其权限为租户套餐的权限
                    if (Objects.equals(role.getRoleCode(), RoleCodeEnum.TENANT_ADMIN.getCode())) {
                        roleMenuGateway.rebindRoleMenus(role.getId(), tenantPackage.getMenuIds());
                        return;
                    }
                    // 如果是其他角色，则去掉超过套餐菜单的权限
                    Set<Long> menuIds = roleMenuGateway.getMenuIdsByRoleId(role.getId());
                    menuIds = CollUtil.intersectionDistinct(menuIds, tenantPackage.getMenuIds());
                    roleMenuGateway.rebindRoleMenus(role.getId(), menuIds);
                });
            });
        }
        return save;
    }
} 